﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using PSE.Framework.ErrorLogging;
using PSE.Framework.Configuration;

namespace PSE.ProcessManager.Common.Gateway
{
    /// <summary>
    /// Gateway para recebimento de mensagens.
    /// </summary>
    [Serializable]
    public class ReceiverGateway
    {
        #region Properties

        private Listener _listener = null;

        private IListenerServiceCallback _callbackInstance = null;

        public IListenerServiceCallback CallbackInstance
        {
            get { return _callbackInstance; }

            set { _callbackInstance = value; }
        }


        #endregion

        #region Events

        private ServiceEvents.MessageReceived onReceiveMessage;
        /// <summary>
        /// Delegate disparado ao receber uma mensagem.
        /// </summary>
        public ServiceEvents.MessageReceived OnReceiveMessage
        {
            get { return onReceiveMessage; }
            set
            {
                onReceiveMessage = value;
                if (_listener != null)
                    _listener.OnReceiveMessage = value;
            }
        }

        private ServiceEvents.ClientConnected onConnect;
        /// <summary>
        /// Delegate disparado ao receber uma mensagem.
        /// </summary>
        public ServiceEvents.ClientConnected OnConnect
        {
            get { return onConnect; }
            set
            {
                onConnect = value;
                if (_listener != null)
                    _listener.OnConnect = value;
            }
        }

        private ServiceEvents.ClientDisconnected onDisconnect;
        /// <summary>
        /// Delegate disparado ao receber uma mensagem.
        /// </summary>
        public ServiceEvents.ClientDisconnected OnDisconnect
        {
            get { return onDisconnect; }
            set
            {
                onDisconnect = value;
                if (_listener != null)
                    _listener.OnDisconnect = value;
            }
        }

        public ServiceEvents.IsProcessRunning IsProcessRunning
        {
            get
            {
                if (_listener != null)
                    return _listener.IsProcessRunning;
                else
                    return null;
            }
            set
            {
                if (_listener != null)
                    _listener.IsProcessRunning = value;
            }
        }

        public ServiceEvents.RetrievedLogList OnRetrieveLogList
        {
            get
            {
                if (_listener != null)
                    return _listener.OnRetrieveLogList;
                else
                    return null;
            }
            set
            {
                if (_listener != null)
                    _listener.OnRetrieveLogList = value;
            }
        }

        public ServiceEvents.RetrievedLastProcessLog OnRetrieveLastProcessLog
        {
            get
            {
                if (_listener != null)
                    return _listener.OnRetrieveLastProcessLog;
                else
                    return null;
            }
            set
            {
                if (_listener != null)
                    _listener.OnRetrieveLastProcessLog = value;
            }
        }

        #endregion

        #region StartListener

        /// <summary>
        /// Inicia o listener para receber mensagens.
        /// </summary>
        /// <param name="address">Endereço do serviço</param>
        /// <param name="protocol">protocolo de comunicação do serviço</param>
        /// <param name="port">Porta de comunicação (apenas para o protocolo Tcp)</param>
        public void StartListener(string address, Protocol protocol)
        {
            try
            {
                _listener = new Listener();
                _listener.Open(address, protocol);
            }
            catch (Exception ex)
            {
                throw new OperationCanceledException("Error trying to open the Listener channel. See inner exceptions for more details.", ex);
            }

        }

        #endregion

        public void SendMessageCallback(BaseMessage message)
        {
            if (CallbackInstance != null)
                CallbackInstance.SendMessageCallBack(MessageCreator.CreateMessage(message, ListenerService.Actions.SendMessageCallBack));
        }

        public void SendMessageCallback<T>(Message<T> message)
        {
            if (CallbackInstance != null)
                CallbackInstance.SendMessageCallBack(MessageCreator.CreateMessage((IMessage)message, ListenerService.Actions.SendMessageCallBack));

        }


        //public void BeginSendMessageCallback(BaseMessage message)
        //{
        //    if (CallbackInstance != null)
        //        CallbackInstance.BeginSendMessageCallBack(MessageCreator.CreateMessage(message, ListenerService.Actions.SendMessageCallBack), new AsyncCallback(AsyncResult), null);

        //}

        //public void BeginSendMessageCallback<T>(Message<T> message)
        //{
        //    if (CallbackInstance != null)
        //        CallbackInstance.BeginSendMessageCallBack(MessageCreator.CreateMessage((IMessage)message, ListenerService.Actions.SendMessageCallBack), new AsyncCallback(AsyncResult), null);

        //}



        //private void AsyncResult(IAsyncResult result)
        //{
        //    try
        //    {
        //        if (CallbackInstance != null)
        //            CallbackInstance.EndSendMessageCallBack(result);
        //    }
        //    catch (Exception ex)
        //    {
        //        ErrorLogger.WriteLog(LogType.Error, new Exception("An error ocurred sending callback message.", ex));
        //    }
        //}

        public void BeginSendMessageCallback(BaseMessage message)
        {
            if (CallbackInstance != null &&
                (((ICommunicationObject)CallbackInstance).State == CommunicationState.Created || ((ICommunicationObject)CallbackInstance).State == CommunicationState.Opened))
                CallbackInstance.BeginSendMessageCallBack(MessageCreator.CreateMessage(message, ListenerService.Actions.SendMessageCallBack), new AsyncCallback(AsyncResult), CallbackInstance);
        }

        public void BeginSendMessageCallback<T>(Message<T> message)
        {
            if (CallbackInstance != null &&
                (((ICommunicationObject)CallbackInstance).State == CommunicationState.Created || ((ICommunicationObject)CallbackInstance).State == CommunicationState.Opened))
                CallbackInstance.BeginSendMessageCallBack(MessageCreator.CreateMessage((IMessage)message, ListenerService.Actions.SendMessageCallBack), new AsyncCallback(AsyncResult), CallbackInstance);
        }



        private void AsyncResult(IAsyncResult result)
        {
            try
            {
                IListenerServiceCallback callback = (IListenerServiceCallback)result.AsyncState;

                if (CallbackInstance != null &&
                (((ICommunicationObject)CallbackInstance).State == CommunicationState.Created || ((ICommunicationObject)CallbackInstance).State == CommunicationState.Opened))
                    callback.EndSendMessageCallBack(result);
            }
            catch (Exception ex)
            {
                ErrorLogger.WriteLog(LogType.Error, new Exception("An error ocurred sending callback message.", ex));
            }
        }

        public void Dispose()
        {

        }
    }
}
